import Cesium from "../Ces/Cesium"
import WeContext from "../Core/WeContext"
import WeDataProvider from "./WeDataProvider"
import WeDisplay from "./WeDisplay"
import WeDisplayParameter from "./WeDisplayParameter"
import WeIsolatedPoint from "./WeIsolatedPoint"
import WeUniform from "./WeUniform"

class WeWindStreamline {
  private initialized: boolean = false
  private primitive: WeIsolatedPoint | null = null
  private dataProvider: WeDataProvider
  private display: WeDisplay
  private showLineVolume: boolean
  private maxTakenNum: number = 2
  private mininumPointPerline: number = 100
  private maxinumLevels: number = 1000
  private bufferSize: number = 1024
  private weUniform: WeUniform
  constructor(options) {
    this.display = options.display
    this.dataProvider = options.dataProvider
    this.showLineVolume = options.showLineVolume ?? false
    this.mininumPointPerline = options.mininumPointPerline ?? 1
    this.maxTakenNum = options.maxTakenNum ?? 2
    this.maxinumLevels = options.maxinumLevels ?? 1000
    const floatUniform = {
      extrusion: options.extrusionHeight ?? 0.0,
      scaleZ: WeDisplayParameter.scaleZ,
      pointSize: options.lineWidth ?? 1.0,
      bufferSize: this.bufferSize,
      outlineWidth: options.outlineWidth ?? 1.0,
      colorize: (options.colorize ?? false) ? 1.0 : 0.0
    }

    const vec4Uniform = {
      outlineColor: options.outlineColor,
      localExtent: options.rectangle,
    }

    this.weUniform = new WeUniform({
      floatUniform,
      vec4Uniform,
      name: 'WeIsolatedPointUniforms',
    })

  }

  get colorize() {
    return this.weUniform.Properties.colorize === 1.0
  }

  set colorize(value) {
    this.weUniform.Properties.colorize = value ? 1.0 : 0.0
  }

  updateData(context, image1, image2) {
    if (!this.primitive) {
      return
    }

    this.loadData(context, image1 ?? image2)
  }

  async loadData(context, image) {
    const weContext: WeContext = context.weContext

    this.display.imageryLayer.loadingRef++

    const processor = await weContext.taskProcessorPool.getTaskProcessor()
    console.time('streamlines')
    processor.scheduleTask({
      type: 'streamlines',
      image,
      options: {
        FrontSpeedClipFactor: 1.0,
        EndSpeedClipFactor: 1.0,
        mininumPointPerline: this.mininumPointPerline,
        FilterMin: 25,
        maxTakenNum: this.maxTakenNum,
        maxinumLevels: this.maxinumLevels
      },
    }).then(async (arrayBufferView: any) => {
      const image1 = {
        source: {
          width: this.bufferSize,
          height: this.bufferSize,
          arrayBufferView,
          pixelFormat: Cesium.PixelFormat.RGB,
          pixelDatatype: Cesium.PixelDatatype.FLOAT,
        },
        url: image.url
      }
      if (this.primitive) {
        await this.primitive.updateData({
          image: image1,
          context,
        })
      } else {
        this.rebuild(context, image1)
      }
    }).finally(() => {
      this.display.imageryLayer.loadingRef--
      console.timeEnd('streamlines')
    })
  }

  async rebuild(context, image) {
    this.primitive = this.primitive && this.primitive.destroy()
    this.primitive = new WeIsolatedPoint(
      {
        context,
        image,
        weUniform: this.weUniform,
        display: this.display,
      }
    )
  }

  update(frameState) {
    if (!frameState.passes.render) return
    if (!this.initialized) {
      this.initialized = true
      const image = this.dataProvider.dataRequest.requestCaches[0]
      this.weUniform.Properties.extrusion = image.externalData?.size?.depth ?? 0
      this.loadData(frameState.context, image)
    }

    if (this.weUniform.Properties.scaleZ !== WeDisplayParameter.scaleZ) {
      this.weUniform.Properties.scaleZ = WeDisplayParameter.scaleZ
    }

    this.primitive?.update(frameState)
  }

  isDestroyed() { return false }

  destroy() {
    this.primitive = this.primitive && this.primitive.destroy()
    return Cesium.destroyObject(this)
  }
}

export default WeWindStreamline
